/*
 * Copyright (c) 2018-2023 北京华恒盛世科技有限公司
 * QUICKPOOL is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
*/

#include "subcmd.h"

#define QUEUE_NAME_F 12
#define PRI_F 5
#define STAT_F 15
#define NUM_WIDE 7

static json *queueinfo_2json(struct QuickPoolQueueInfo *, struct quickpoolInfo *);
static void listqueue_usage(const char *);

/**
 * @brief       qp queue list handler, to query queue information from js.
 *
 * @param[in]   argc          #1: number of input argument
 * @param[in]   argv          #2: string array of the input argument
 *
 * @retval      0             #1: succeed
 * @retval      1             #2: input option is wrong or kind of input argument not specified
 * @retval      2             #3: argument has syntax error
 * @retval      3             #4: failed to query queue information
 * @retval      4             #5: not enough memory to print json string
 */
int
cmd_list_queues(int argc, char **argv)
{
    unsigned int options=0;
    char *strNode=NULL, *strUser=NULL;
    bool_t fOpt = FALSE;
    bool_t wOpt = FALSE;
    while (TRUE) {
        int option_index = 0;
        static struct option long_options[] = {
            {"help", no_argument, 0, 'h'},
            {"node", required_argument, 0, 'm'},
            {"user", required_argument, 0, 'u'},
            {"format", no_argument, 0, 'f'},
            {"wide", no_argument, 0, 'w'},
            {NULL, 0, 0, 0}
        };
        
        int opt;
        opt = getopt_long(argc, argv, "hm:fwu:", long_options, &option_index);
        if (-1 == opt) {
            break;
        }

        switch (opt) {
        case 'm':
            if (NULL != strNode) {
                fprintf(stderr, "Do not specify -m option for multiple times.\n");
                listqueue_usage(argv[0]);
                exit(1);
            }

            if (0 >= strlen(optarg)) {
                fprintf(stderr, "Specify a node name with -m option.\n");
                listqueue_usage(argv[0]);
                exit(1);
            }

            strNode = optarg;
            options |= CHECK_HOST;

            break;
        case 'u':
            if (NULL != strUser) {
                fprintf(stderr, "Do not specify -u option for multiple times.\n");
                listqueue_usage(argv[0]);
                exit(1);
            }

            if (0 >= strlen(optarg)) {
                fprintf(stderr, "Specify a user name with -u option.\n");
                listqueue_usage(argv[0]);
                exit(1);
            }

            strUser = optarg;
            options |= CHECK_USER;

            break;
        case 'f':
            fOpt = TRUE;
            break;
        case 'w':
            wOpt = TRUE;
            break;
        case 'h':
            listqueue_usage(argv[0]);
            exit(0);
        case '?':
        default:
            listqueue_usage(argv[0]);
            exit(1);
        }
    }

    // if not specify queue name, set all to TRUE
    unsigned int numQueue;
    int all=FALSE;
    char **queues=NULL, **queuePoint=NULL;
    numQueue = get_argument_names(argc, argv, optind, &queues, &all, "queue");
    if (!all && 0 != numQueue) {
        queuePoint = queues;
    } else {
        options |= ALL_QUEUE;
    }

    struct request queueRequest;
    memset(&queueRequest, 0, sizeof(struct request));

    queueRequest.keyvalues = (struct keyvalue *)calloc(5, sizeof(struct keyvalue));
    if (NULL == queueRequest.keyvalues) {
        fprintf(stderr, "calloc(%ld) failed due to %m.\n",
                5*sizeof(struct keyvalue));
        exit(4);
    }

    unsigned int n = 0;
    queueRequest.keyvalues[n].key = REQUEST_KEY_OPTIONS;
    queueRequest.keyvalues[n].value = (char *)calloc(12, sizeof(char));
    if (NULL == queueRequest.keyvalues[n].value) {
        fprintf(stderr, "calloc(%d) failed due to %m.\n", 12);
        exit(4);
    }
    snprintf(queueRequest.keyvalues[n].value, 12, "%d", options);
    n ++;

    if (0 < numQueue) {

        // to query specific queues.
        queueRequest.keyvalues[n].key = REQUEST_KEY_NUMBER;
        queueRequest.keyvalues[n].value = (char *)calloc(12, sizeof(char));
        if (NULL == queueRequest.keyvalues[n].value) {
            fprintf(stderr, "calloc(%d) failed due to %m.\n", 12);
            exit(4);
        }
        snprintf(queueRequest.keyvalues[n].value, 12, "%d", numQueue);
        n ++;

        queueRequest.keyvalues[n].key = REQUEST_KEY_NAMES;
        unsigned int i, size = 0;
        for (i = 0; i < numQueue; i++) {
            size += strlen(queuePoint[i]) + 1;
        }
        queueRequest.keyvalues[n].value = (char *)calloc(size+1, sizeof(char));
        if (NULL == queueRequest.keyvalues[n].value) {
            fprintf(stderr, "calloc(%d) failed due to %m.\n", size);
            exit(4);
        }

        for (i = 0; i < numQueue; i++) {
            if (i == 0) {
                strncpy(queueRequest.keyvalues[n].value, queuePoint[i], size);
            } else {
                strncat(queueRequest.keyvalues[n].value, " ", size);
                strncat(queueRequest.keyvalues[n].value, queuePoint[i], size);
            }
        }
        n ++;
    }

    if (NULL != strUser) {
        queueRequest.keyvalues[n].key = REQUEST_KEY_CHECKUSER;
        queueRequest.keyvalues[n].value = copy_string(strUser);
        n ++;
    }

    if (NULL != strNode) {
        queueRequest.keyvalues[n].key = REQUEST_KEY_CHECKHOST;
        queueRequest.keyvalues[n].value = copy_string(strNode);
        n ++;
    }
    queueRequest.number = n;

    FREEUP(queues);

    quickpool_errno = 0;
    struct QuickPoolQueueReply *queueReply;
    queueReply = client_get_queueinfo(&queueRequest, NULL);
    if (quickpool_errno != 0 || NULL == queueReply) {

        if (NULL == queueReply) {
            fprintf(stderr, "Fail to query queue list due to above error.\n");
            gf_xdr_free(gf_xdr_request, &queueRequest);
            exit(3);
        }

        // JS replied error message.
        fprintf(stderr, "%s\n", queueReply->error_message);

        gf_xdr_free(libxdr_queue_reply, queueReply);
        FREEUP(queueReply);
        gf_xdr_free(gf_xdr_request, &queueRequest);

        exit(3);
    }
    gf_xdr_free(gf_xdr_request, &queueRequest);

    struct quickpoolInfo *qpInfo;
    qpInfo = qp_info(NULL);
    if (NULL == qpInfo) {
        exit(3);
    }
    
    if ((fOpt | wOpt) && 0 < queueReply->num_queue) {
        char buf[4096+1];
        char header[4096+1];
        snprintf(buf, 4096, "%%-%ds  %%%dd  %%-%ds  %%%ds  %%%dd  %%%dd  %%%dd  %%%dd\n",
                 QUEUE_NAME_F, PRI_F, STAT_F, NUM_WIDE, NUM_WIDE, NUM_WIDE, NUM_WIDE, NUM_WIDE);
        snprintf(header, 4096, "%%-%ds  %%%ds  %%-%ds  %%%ds  %%%ds  %%%ds  %%%ds  %%%ds\n",
                 QUEUE_NAME_F, PRI_F, STAT_F, NUM_WIDE, NUM_WIDE, NUM_WIDE, NUM_WIDE, NUM_WIDE);
        fprintf(stdout,header, "QUEUE_NAME", "PRI", "STAT", "MAX", "TOTAL", "PEND", "RUN","SUSP");
        char stat[128];
        char str_max_slot[12];

        unsigned int k;
        for(k = 0; k < queueReply->num_queue; k++){
            get_queuestatus(&queueReply->queues[k],stat);
            if (strlen(queueReply->queues[k].queue) > QUEUE_NAME_F && wOpt == FALSE) {
                queueReply->queues[k].queue[QUEUE_NAME_F-1] = '*';
                queueReply->queues[k].queue[QUEUE_NAME_F] = '\0';
            } else {
                if (queueReply->queues[k].max_num_slot == INFINIT_INT) {
                    snprintf(str_max_slot, 12, "-");
                } else {
                    snprintf(str_max_slot, 12, "%d", queueReply->queues[k].max_num_slot);
                }
                fprintf(stdout,buf,queueReply->queues[k].queue,queueReply->queues[k].priority,
                                    stat,str_max_slot,queueReply->queues[k].num_job_slot,
                            queueReply->queues[k].num_pending_slot,queueReply->queues[k].num_running_slot,queueReply->queues[k].num_SSUSP_slot+queueReply->queues[k].num_USUSP_slot);
                continue;
            }
            fprintf(stdout,buf,queueReply->queues[k].queue,queueReply->queues[k].priority,
                                    stat,str_max_slot,queueReply->queues[k].num_job_slot,
                            queueReply->queues[k].num_pending_slot,queueReply->queues[k].num_running_slot,queueReply->queues[k].num_SSUSP_slot+queueReply->queues[k].num_USUSP_slot);
        }
        
        gf_xdr_free(libxdr_queue_reply, queueReply);
        FREEUP(queueReply);
        exit(0);
    }

    json *jsonQueueList = json_CreateObject();
    unsigned int i;
    for (i=0; i<queueReply->num_queue; i++) {

        json *jsonQueue = queueinfo_2json(&(queueReply->queues[i]), qpInfo);
        json_AddItemToObject(jsonQueueList, queueReply->queues[i].queue, jsonQueue);
    }

    if (0 < json_GetArraySize(jsonQueueList)) {
        char *strJson;
        strJson = json_Print(jsonQueueList);
        if (NULL != strJson) {
            fprintf(stdout, "%s\n", strJson);
            FREEUP(strJson);
        } else {

            perror("malloc");
            json_Delete(jsonQueueList);
            gf_xdr_free(libxdr_queue_reply, queueReply);
            FREEUP(queueReply);

            exit(4);
        }
    } else {
        // nothing in json means there's no queue in the cluster, should not go here.
        fprintf(stderr, "No queue information in the cluster.\n");
    }
    json_Delete(jsonQueueList);

    gf_xdr_free(libxdr_queue_reply, queueReply);
    FREEUP(queueReply);

    return 0;
} // end function cmd_list_queues

/* ------------------------------------------------
 *
 *  below are static functions used in this file
 *
 * ------------------------------------------------ */

/**
 * @brief       transform queue structure to json.
 *
 * @param[in]   queue         #1: queue to be tranformed
 * @param[in]   info          #2: load index and resource table
 *
 * @retval      not NULL      #1: transformed json object
 */
static json *
queueinfo_2json(struct QuickPoolQueueInfo *queue, struct quickpoolInfo *info)
{
    json *jsonQueue = json_CreateObject();

    s2j_json_set_basic_element(jsonQueue, queue, string, "QUEUE", queue);
    s2j_json_set_basic_element(jsonQueue, queue, int, "PRIORITY", priority);
    s2j_json_set_basic_element(jsonQueue, queue, int, "NICE", nice);

    char stat[20];
    get_queuestatus(queue,stat);
    json_AddStringToObject(jsonQueue, "STATUS", stat);

    if (queue->max_num_slot < INFINIT_INT) {
        s2j_json_set_basic_element(jsonQueue, queue, int, "MAX", max_num_slot);
    }

    if (queue->user_slot_limit < INFINIT_INT) {
        s2j_json_set_basic_element(jsonQueue, queue, int, "UJOB_LIMIT", user_slot_limit);
    }

    if (queue->host_slot_limit < INFINIT_INT) {
        s2j_json_set_basic_element(jsonQueue, queue, int, "HJOB_LIMIT", host_slot_limit);
    }

    if (queue->job_slot_limit < INFINIT_INT) {
        char procLimit[64+1];

        snprintf(procLimit, 64, "%d %d %d",
                 queue->min_job_slot, queue->default_job_slot, queue->job_slot_limit);
        json_AddStringToObject(jsonQueue, "PROCLIMIT", procLimit);
    }

    s2j_json_set_basic_element(jsonQueue, queue, int, "NSLOTS", num_job_slot);
    s2j_json_set_basic_element(jsonQueue, queue, int, "PEND", num_pending_slot);
    s2j_json_set_basic_element(jsonQueue, queue, int, "RUN", num_running_slot);
    s2j_json_set_basic_element(jsonQueue, queue, int, "SSUSP", num_SSUSP_slot);
    s2j_json_set_basic_element(jsonQueue, queue, int, "USUSP", num_USUSP_slot);
    s2j_json_set_basic_element(jsonQueue, queue, int, "RSV", num_reserving_slot);

    if (queue->mig < INFINIT_INT) {

        s2j_json_set_basic_element(jsonQueue, queue, int, "MIG", mig);
    }

    if (queue->schedule_policy & QUEUE_POLICY_RERUNNABLE) {
        json_AddTrueToObject(jsonQueue, "RERUNNABLE");
    }

    if (queue->job_dispatch_interval < INFINIT_INT) {

        s2j_json_set_basic_element(jsonQueue, queue, int, "JOB_ACCEPT_INTERVAL", job_dispatch_interval);
    }

    if (queue->job_schedule_delay < INFINIT_INT) {

        s2j_json_set_basic_element(jsonQueue, queue, int, "NEW_JOB_SCHED_DELAY", job_schedule_delay);
    }

    if (0 < queue->reservation_time) {
        s2j_json_set_basic_element(jsonQueue, queue, int, "MAX_RESERVE_TIME", reservation_time);
    }

    if (queue->schedule_policy & QUEUE_POLICY_PREEMPTIVE) {

        s2j_json_set_basic_element(jsonQueue, queue, string, "PREEMPTION", preemption);
    }

    if (NULL != queue->run_window && strlen(queue->run_window) > 0) {

        s2j_json_set_basic_element(jsonQueue, queue, string, "RUN_WINDOW", run_window);
    }

    if (NULL != queue->dispatch_window && strlen(queue->dispatch_window) > 0) {

        s2j_json_set_basic_element(jsonQueue, queue, string, "DISPATCH_WINDOW", dispatch_window);
    }

    s2j_json_set_basic_element(jsonQueue, queue, string, "USERS", users);
    s2j_json_set_basic_element(jsonQueue, queue, string, "HOSTS", hosts);

    if (NULL != queue->administrators && strlen(queue->administrators) > 0) {

        s2j_json_set_basic_element(jsonQueue, queue, string, "ADMINISTRATORS", administrators);
    }

    if (NULL != queue->prejob_command && strlen(queue->prejob_command) > 0) {
        s2j_json_set_basic_element(jsonQueue, queue, string, "PRE_EXEC", prejob_command);
    }

    if (NULL != queue->postjob_command && strlen(queue->postjob_command) > 0) {
        s2j_json_set_basic_element(jsonQueue, queue, string, "POST_EXEC", postjob_command);
    }

    unsigned int limit;
    for (limit=0; limit<RESOURCE_LIMIT_NUM; limit++) {
        char strLimit[32+1];
        memset(strLimit, 0, 32);

        switch (limit) {
	case RESOURCE_LIMIT_CPU:
            if (queue->default_ulimit[RESOURCE_LIMIT_CPU] != INFINIT_INT
                && queue->default_ulimit[RESOURCE_LIMIT_CPU] > 0) {

                snprintf(strLimit, 32, "%d %d", queue->default_ulimit[RESOURCE_LIMIT_CPU],
                         queue->queue_ulimit[RESOURCE_LIMIT_CPU]);
                json_AddStringToObject(jsonQueue, "CPULIMIT", strLimit);
            } else if (queue->queue_ulimit[RESOURCE_LIMIT_CPU] != INFINIT_INT
                       && queue->queue_ulimit[RESOURCE_LIMIT_CPU] > 0) {

                snprintf(strLimit, 32, "%d", queue->queue_ulimit[RESOURCE_LIMIT_CPU]);
                json_AddStringToObject(jsonQueue, "CPULIMIT", strLimit);
            }

            break;
	case RESOURCE_LIMIT_RUN:
            if (queue->default_ulimit[RESOURCE_LIMIT_RUN] != INFINIT_INT
                && queue->default_ulimit[RESOURCE_LIMIT_RUN] > 0) {

                snprintf(strLimit, 32, "%d %d", queue->default_ulimit[RESOURCE_LIMIT_RUN],
                         queue->queue_ulimit[RESOURCE_LIMIT_RUN]);
                json_AddStringToObject(jsonQueue, "RUNLIMIT", strLimit);
            } else if (queue->queue_ulimit[RESOURCE_LIMIT_RUN] != INFINIT_INT
                       && queue->queue_ulimit[RESOURCE_LIMIT_RUN] > 0) {

                snprintf(strLimit, 32, "%d", queue->queue_ulimit[RESOURCE_LIMIT_RUN]);
                json_AddStringToObject(jsonQueue, "RUNLIMIT", strLimit);
            }

            break;
	case RESOURCE_LIMIT_DATA:
            if (queue->default_ulimit[RESOURCE_LIMIT_DATA] != INFINIT_INT
                && queue->default_ulimit[RESOURCE_LIMIT_DATA] > 0) {

                snprintf(strLimit, 32, "%d %d", queue->default_ulimit[RESOURCE_LIMIT_DATA],
                         queue->queue_ulimit[RESOURCE_LIMIT_DATA]);
                json_AddStringToObject(jsonQueue, "DATALIMIT", strLimit);
            } else if (queue->queue_ulimit[RESOURCE_LIMIT_DATA] != INFINIT_INT
                       && queue->queue_ulimit[RESOURCE_LIMIT_DATA] > 0) {

                snprintf(strLimit, 32, "%d", queue->queue_ulimit[RESOURCE_LIMIT_DATA]);
                json_AddStringToObject(jsonQueue, "DATALIMIT", strLimit);
            }

            break;
	case RESOURCE_LIMIT_FSIZE:
            if (queue->default_ulimit[RESOURCE_LIMIT_FSIZE] != INFINIT_INT
                && queue->default_ulimit[RESOURCE_LIMIT_FSIZE] > 0) {

                snprintf(strLimit, 32, "%d %d", queue->default_ulimit[RESOURCE_LIMIT_FSIZE],
                         queue->queue_ulimit[RESOURCE_LIMIT_FSIZE]);
                json_AddStringToObject(jsonQueue, "FILELIMIT", strLimit);
            } else if (queue->queue_ulimit[RESOURCE_LIMIT_FSIZE] != INFINIT_INT
                       && queue->queue_ulimit[RESOURCE_LIMIT_FSIZE] > 0) {

                snprintf(strLimit, 32, "%d", queue->queue_ulimit[RESOURCE_LIMIT_FSIZE]);
                json_AddStringToObject(jsonQueue, "FILELIMIT", strLimit);
            }

            break;
	case RESOURCE_LIMIT_STACK:
            if (queue->default_ulimit[RESOURCE_LIMIT_STACK] != INFINIT_INT
                && queue->default_ulimit[RESOURCE_LIMIT_STACK] > 0) {

                snprintf(strLimit, 32, "%d %d", queue->default_ulimit[RESOURCE_LIMIT_STACK],
                         queue->queue_ulimit[RESOURCE_LIMIT_STACK]);
                json_AddStringToObject(jsonQueue, "STACKLIMIT", strLimit);
            } else if (queue->queue_ulimit[RESOURCE_LIMIT_STACK] != INFINIT_INT
                       && queue->queue_ulimit[RESOURCE_LIMIT_STACK] > 0) {

                snprintf(strLimit, 32, "%d", queue->queue_ulimit[RESOURCE_LIMIT_STACK]);
                json_AddStringToObject(jsonQueue, "STACKLIMIT", strLimit);
            }

            break;
	case RESOURCE_LIMIT_CORE:
            if (queue->default_ulimit[RESOURCE_LIMIT_CORE] != INFINIT_INT
                && queue->default_ulimit[RESOURCE_LIMIT_CORE] > 0) {

                snprintf(strLimit, 32, "%d %d", queue->default_ulimit[RESOURCE_LIMIT_CORE],
                         queue->queue_ulimit[RESOURCE_LIMIT_CORE]);
                json_AddStringToObject(jsonQueue, "CORELIMIT", strLimit);
            } else if (queue->queue_ulimit[RESOURCE_LIMIT_CORE] != INFINIT_INT
                       && queue->queue_ulimit[RESOURCE_LIMIT_CORE] > 0) {

                snprintf(strLimit, 32, "%d", queue->queue_ulimit[RESOURCE_LIMIT_CORE]);
                json_AddStringToObject(jsonQueue, "CORELIMIT", strLimit);
            }

            break;
	case RESOURCE_LIMIT_RSS:
            if (queue->default_ulimit[RESOURCE_LIMIT_RSS] != INFINIT_INT
                && queue->default_ulimit[RESOURCE_LIMIT_RSS] > 0) {

                snprintf(strLimit, 32, "%d %d", queue->default_ulimit[RESOURCE_LIMIT_RSS],
                         queue->queue_ulimit[RESOURCE_LIMIT_RSS]);
                json_AddStringToObject(jsonQueue, "MEMLIMIT", strLimit);
            } else if (queue->queue_ulimit[RESOURCE_LIMIT_RSS] != INFINIT_INT
                       && queue->queue_ulimit[RESOURCE_LIMIT_RSS] > 0) {

                snprintf(strLimit, 32, "%d", queue->queue_ulimit[RESOURCE_LIMIT_RSS]);
                json_AddStringToObject(jsonQueue, "MEMLIMIT", strLimit);
            }

            break;
	case RESOURCE_LIMIT_SWAP:
            if (queue->default_ulimit[RESOURCE_LIMIT_SWAP] != INFINIT_INT
                && queue->default_ulimit[RESOURCE_LIMIT_SWAP] > 0) {

                snprintf(strLimit, 32, "%d %d", queue->default_ulimit[RESOURCE_LIMIT_SWAP],
                         queue->queue_ulimit[RESOURCE_LIMIT_SWAP]);
                json_AddStringToObject(jsonQueue, "SWAPLIMIT", strLimit);
            } else if (queue->queue_ulimit[RESOURCE_LIMIT_SWAP] != INFINIT_INT
                       && queue->queue_ulimit[RESOURCE_LIMIT_SWAP] > 0) {

                snprintf(strLimit, 32, "%d", queue->queue_ulimit[RESOURCE_LIMIT_SWAP]);
                json_AddStringToObject(jsonQueue, "SWAPLIMIT", strLimit);
            }

            break;
	case RESOURCE_LIMIT_PROCESS:
            if (queue->default_ulimit[RESOURCE_LIMIT_PROCESS] != INFINIT_INT
                && queue->default_ulimit[RESOURCE_LIMIT_PROCESS] > 0) {

                snprintf(strLimit, 32, "%d %d", queue->default_ulimit[RESOURCE_LIMIT_PROCESS],
                         queue->queue_ulimit[RESOURCE_LIMIT_PROCESS]);
                json_AddStringToObject(jsonQueue, "PROCESSLIMIT", strLimit);
            } else if (queue->queue_ulimit[RESOURCE_LIMIT_PROCESS] != INFINIT_INT
                       && queue->queue_ulimit[RESOURCE_LIMIT_PROCESS] > 0) {

                snprintf(strLimit, 32, "%d", queue->queue_ulimit[RESOURCE_LIMIT_PROCESS]);
                json_AddStringToObject(jsonQueue, "PROCESSLIMIT", strLimit);
            }

            break;
        }
    }

    json *jsonLoadSchedule;
    jsonLoadSchedule = json_CreateObject();

    json *jsonLoadStop;
    jsonLoadStop = json_CreateObject();

    unsigned int i;
    for (i=0; i<info->num_index; i++) {
        char strLoadSchedule[64+1];
        char strLoadStop[64+1];
        strLoadSchedule[0] = '\0';
        strLoadStop[0] = '\0';

        if (queue->load_schedule[i] < INFINIT_LOAD && queue->load_schedule[i] > -INFINIT_LOAD) {
            snprintf(strLoadSchedule, 64, "%.2f", queue->load_schedule[i]);
        }

        if (queue->load_stop[i] < INFINIT_LOAD && queue->load_stop[i] > -INFINIT_LOAD) {
            snprintf(strLoadStop, 64, "%.2f", queue->load_stop[i]);
        }

        if (0 < strlen(strLoadSchedule)) {
            json_AddStringToObject(jsonLoadSchedule, info->resource_table[i].name, strLoadSchedule);
        }

        if (0 < strlen(strLoadStop)) {
            json_AddStringToObject(jsonLoadStop, info->resource_table[i].name, strLoadStop);
        }
    }

    if (0 < json_GetArraySize(jsonLoadSchedule)) {
        json_AddItemToObject(jsonQueue, "LOAD_SCHED", jsonLoadSchedule);
    } else {
        json_Delete(jsonLoadSchedule);
    }

    if (0 < json_GetArraySize(jsonLoadStop)) {
        json_AddItemToObject(jsonQueue, "LOAD_STOP", jsonLoadStop);
    } else {
        json_Delete(jsonLoadStop);
    }

    if (NULL != queue->requeue_exitcode && strlen(queue->requeue_exitcode) > 0) {

        s2j_json_set_basic_element(jsonQueue, queue, string, "REQUEUE_EXIT_VALUES", requeue_exitcode);
    }

    if (NULL != queue->resume_condition && strlen(queue->resume_condition) > 0) {

        s2j_json_set_basic_element(jsonQueue, queue, string, "RESUME_COND", resume_condition);
    }

    if (NULL != queue->stop_condition && strlen(queue->stop_condition) > 0) {

        s2j_json_set_basic_element(jsonQueue, queue, string, "STOP_COND", stop_condition);
    }

    if (NULL != queue->job_starter && strlen(queue->job_starter) > 0) {

        s2j_json_set_basic_element(jsonQueue, queue, string, "JOB_STARTER", job_starter);
    }

    if (NULL != queue->prepost_user && strlen(queue->prepost_user) > 0) {

        s2j_json_set_basic_element(jsonQueue, queue, string, "PRE_POST_EXEC_USER", prepost_user);
    }

    if (NULL != queue->resource_requirement && strlen(queue->resource_requirement) > 0) {

        s2j_json_set_basic_element(jsonQueue, queue, string, "RES_REQ", resource_requirement);
    }

    char strCommand[4096*3+1];
    strCommand[0] = '\0';
    if (NULL != queue->suspend_command && strlen(queue->suspend_command) > 0) {
        snprintf(strCommand, 4096*3, "SUSPEND[%s]", queue->suspend_command);
    }
    if (NULL != queue->resume_command && strlen(queue->resume_command) > 0) {
        if (0 == strlen(strCommand)) {
            snprintf(strCommand, 4096*3, "RESUME[%s]", queue->resume_command);
        } else {
            snprintf(strCommand+strlen(strCommand), 4096*3, " RESUME[%s]", queue->resume_command);
        }
    }
    if (NULL != queue->terminate_command && strlen(queue->terminate_command) > 0) {
        if (0 == strlen(strCommand)) {
            snprintf(strCommand, 4096*3, "TERMINATE[%s]", queue->terminate_command);
        } else {
            snprintf(strCommand+strlen(strCommand), 4096*3, " TERMINATE[%s]",
                     queue->terminate_command);
        }
    }

    if (0 < strlen(strCommand)) {
        json_AddStringToObject(jsonQueue, "JOB_CONTROLS", strCommand);
    }

    char strSuspend[56];
    strSuspend[0] = '\0';
    bool_t userSuspend;
    bool_t preemptSuspend;
    bool_t windowSuspend;
    bool_t loadSuspend;
    userSuspend = suspend_terminate_defined(queue->quickpool_signal, "USER");
    preemptSuspend = suspend_terminate_defined(queue->quickpool_signal, "PREEMPT");
    windowSuspend = suspend_terminate_defined(queue->quickpool_signal, "WINDOW");
    loadSuspend = suspend_terminate_defined(queue->quickpool_signal, "LOAD");
    if (userSuspend) {
        strcpy(strSuspend, "USER");
    }
    if (preemptSuspend) {
        if (!userSuspend) {
            strcpy(strSuspend, "PREEMPT");
        } else {
            strcat(strSuspend, " ");
            strcat(strSuspend, "PREEMPT");
        }
    }
    if (windowSuspend) {
        if (!userSuspend && !preemptSuspend) {
            strcpy(strSuspend, "WINDOW");
        } else {
            strcat(strSuspend, " ");
            strcat(strSuspend, "WINDOW");
        }
    }
    if (loadSuspend) {
        if (!userSuspend && !preemptSuspend && !windowSuspend) {
            strcpy(strSuspend, "LOAD");
        } else {
            strcat(strSuspend, " ");
            strcat(strSuspend, "LOAD");
        }
    }

    if (0 < strlen(strSuspend)) {
        json_AddStringToObject(jsonQueue, "TERMINATE_WHEN", strSuspend);
    }

    if (queue->schedule_policy & QUEUE_POLICY_CHKPNT) {
        s2j_json_set_basic_element(jsonQueue, queue, string, "CHKPNT_DIR", chkpnt_dir);
        s2j_json_set_basic_element(jsonQueue, queue, int, "CHKPNT_PERIOD", chkpnt_period);
    }

    char strSchedule[256];
    strSchedule[0] = '\0';
    if (queue->schedule_policy & QUEUE_POLICY_FAIRSHARE) {
        strcpy(strSchedule, "FAIRSHARE");
    }
    if (queue->schedule_policy & QUEUE_POLICY_OWNERSHIP) {
        if (0 == strlen(strSchedule)) {
            strcpy(strSchedule, "OWNED_SLOTS");
        } else {
            strcat(strSchedule, " ");
            strcat(strSchedule, "OWNED_SLOTS");
        }
    }
    if (queue->schedule_policy & QUEUE_POLICY_EXCLUSIVE) {
        if (0 == strlen(strSchedule)) {
            strcpy(strSchedule, "EXCLUSIVE");
        } else {
            strcat(strSchedule, " ");
            strcat(strSchedule, "EXCLUSIVE");
        }
    }
    if (queue->schedule_policy & QUEUE_POLICY_PREEMPTIVE) {
        if (0 == strlen(strSchedule)) {
            strcpy(strSchedule, "PREEMPTION");
        } else {
            strcat(strSchedule, " ");
            strcat(strSchedule, "PREEMPTION");
        }
    }
    if (queue->schedule_policy & QUEUE_POLICY_BACKFILL) {
        if (0 == strlen(strSchedule)) {
            strcpy(strSchedule, "BACKFILL");
        } else {
            strcat(strSchedule, " ");
            strcat(strSchedule, "BACKFILL");
        }
    }
    if (queue->schedule_policy & QUEUE_POLICY_IGNORE_DEADLINE) {
        if (0 == strlen(strSchedule)) {
            strcpy(strSchedule, "IGNORE_DEADLINE");
        } else {
            strcat(strSchedule, " ");
            strcat(strSchedule, "IGNORE_DEADLINE");
        }
    }
    if (queue->schedule_policy & QUEUE_POLICY_ROUND_ROBIN) {
        if (0 == strlen(strSchedule)) {
            strcpy(strSchedule, "ROUND_ROBIN");
        } else {
            strcat(strSchedule, " ");
            strcat(strSchedule, "ROUND_ROBIN");
        }
    }

    if (0 < strlen(strSchedule)) {
        json_AddStringToObject(jsonQueue, "SCHEDULE_POLICIES", strSchedule);
    }

    if (queue->schedule_policy & QUEUE_POLICY_FAIRSHARE) {

        for (i=0; i<queue->num_fairshare_account; i++) {
            json *jsonFairshare = json_CreateObject();

            json_AddItemToObject(jsonQueue, "USER_SHARES", jsonFairshare);

            s2j_json_set_basic_element(jsonFairshare, queue->fairshare_accounts[i],
                                       string, "USER/GROUP", name);
            s2j_json_set_basic_element(jsonFairshare, queue->fairshare_accounts[i],
                                       int, "SHARES", shares);
            s2j_json_set_basic_element(jsonFairshare, queue->fairshare_accounts[i],
                                       double, "PROPORTION", dshares);
            s2j_json_set_basic_element(jsonFairshare, queue->fairshare_accounts[i],
                                       int, "PEND", numPEND);
            s2j_json_set_basic_element(jsonFairshare, queue->fairshare_accounts[i],
                                       int, "RUN", numRUN);
        }
    }

    if (queue->schedule_policy & QUEUE_POLICY_OWNERSHIP) {

        for (i=0; i<queue->num_fairshare_account; i++) {
            json *jsonFairshare = json_CreateObject();

            json_AddItemToObject(jsonQueue, "USER_SHARES", jsonFairshare);

            s2j_json_set_basic_element(jsonFairshare, queue->fairshare_accounts[i],
                                       string, "USER/GROUP", name);
            s2j_json_set_basic_element(jsonFairshare, queue->fairshare_accounts[i],
                                       int, "SHARES", shares);
            s2j_json_set_basic_element(jsonFairshare, queue->fairshare_accounts[i],
                                       int, "PEND", numPEND);
            s2j_json_set_basic_element(jsonFairshare, queue->fairshare_accounts[i],
                                       int, "RUN", numRUN);
            s2j_json_set_basic_element(jsonFairshare, queue->fairshare_accounts[i],
                                       int, "BORROWED", numBORROWED);
        }
    }

    s2j_json_set_basic_element(jsonQueue, queue, string, "DESCRIPTION", description);

    return jsonQueue;
} // end function queueinfo_2json

static void
listqueue_usage(const char *cmd)
{
    fprintf(stdout, "qp queue %s usage: [-h, --help] [-f,--format] [-w,--wide] [-m, --node host_name]\n", cmd);
    fprintf(stdout, "\t\t     [-u, --user user_name] [queue_name ...]\n");

    return;
}
char *
get_queuestatus(struct QuickPoolQueueInfo *queue, char stat[])
{
    if (queue->queue_status & QUEUE_STATUS_OPEN) {

        if ((queue->queue_status & QUEUE_STATUS_ACTIVE) && (queue->queue_status & QUEUE_STATUS_RUN)) {
            strcpy(stat,"Open,Active");
        }

        if ((queue->queue_status & QUEUE_STATUS_ACTIVE) && !(queue->queue_status & QUEUE_STATUS_RUN)) {
            strcpy(stat,"Open,Inact_Win");
        }

        if (!(queue->queue_status & QUEUE_STATUS_ACTIVE)) {
            strcpy(stat,"Open,Inact_Adm");
        }
    } else {

        if ((queue->queue_status & QUEUE_STATUS_ACTIVE) && (queue->queue_status & QUEUE_STATUS_RUN)) {
            strcpy(stat,"Closed,Active");
        }

        if ((queue->queue_status & QUEUE_STATUS_ACTIVE) && !(queue->queue_status & QUEUE_STATUS_RUN)) {
            strcpy(stat,"Closed,Inact_Win");
        }

        if (!(queue->queue_status & QUEUE_STATUS_ACTIVE)) {
            strcpy(stat,"Closed,Inact_Adm");
        }
    }
    return stat;
}
